package com.aloda.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.aloda.cache.RedisUtils;
import com.aloda.constant.ErrorCode;
import com.aloda.constant.ExceptionConstant;
import com.aloda.constant.RedisConstant;
import com.aloda.constant.UserConstant;
import com.aloda.context.UserBaseContext;
import com.aloda.dto.user.*;
import com.aloda.entity.User;
import com.aloda.entity.UserFollow;
import com.aloda.enums.AppAuthEnum;
import com.aloda.enums.CollectAuthEnum;
import com.aloda.enums.UserStatus;
import com.aloda.exception.BaseException;
import com.aloda.exception.WarnException;
import com.aloda.mapper.FollowMapper;
import com.aloda.mapper.UserMapper;
import com.aloda.properties.SaltProperties;
import com.aloda.properties.TokenProperties;
import com.aloda.query.ScrollingPageQuery;
import com.aloda.query.SearchPageDTO;
import com.aloda.query.UserCardPageQuery;
import com.aloda.query.UserPageDTO;
import com.aloda.result.PageResult;
import com.aloda.service.UserService;
import com.aloda.utils.CheckUtils;
import com.aloda.vo.user.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author aloda
 * @description 针对表【user(用户表)】的数据库操作Service实现
 * @createDate 2024-12-26 11:26:18
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private TokenProperties tokenProperties;

    @Resource
    private SaltProperties saltProperties;

    @Resource
    private UserMapper userMapper;

    @Resource
    private FollowMapper followMapper;

    /**
     * 通过手机号进行注册
     *
     * @param userRegisterDTO
     */
    @Override
    public void registerByPhone(UserRegisterDTO userRegisterDTO) {
        // 1.校验数据格式
        if (!CheckUtils.checkAccount(userRegisterDTO.getUserAccount())) {
            throw new WarnException(ExceptionConstant.ACCOUNT_ERROR);
        }
        if (!CheckUtils.checkPassword(userRegisterDTO.getUserPassword())) {
            throw new WarnException(ExceptionConstant.PASSWORD_ERROR);
        }
        if (!CheckUtils.checkPhone(userRegisterDTO.getPhone())) {
            throw new WarnException(ExceptionConstant.PHONE_ERROR);
        }
        if (!CheckUtils.checkPhoneCode(userRegisterDTO.getCode())) {
            throw new WarnException(ExceptionConstant.PHONE_CODE_ERROR);
        }
        // 2.根据手机号查询是否有对应的验证码缓存 2.1没有返回验证码错误
        String result = stringRedisTemplate.opsForValue().get(RedisConstant.PHONE_CODE_KEY + userRegisterDTO.getPhone());
        if (result == null || result.isEmpty()) {
            throw new WarnException(ExceptionConstant.PHONE_CODE_ERROR);
        }
        // 3.判断验证码是否正确 错误返回验证码错误
        if (!userRegisterDTO.getCode().equals(result)) {
            throw new WarnException(ExceptionConstant.PHONE_CODE_ERROR);
        }
        // 验证码正确一次后直接失效
        stringRedisTemplate.delete(RedisConstant.PHONE_CODE_KEY + userRegisterDTO.getPhone());
        // 4.判断该手机号/账号是否注册过 1.返回该手机号已注册 2.返回账号已注册过请换一个
        checkPhoneAndAccount(userRegisterDTO.getPhone(), userRegisterDTO.getUserAccount());
        // 5.密码加密
        String encryptUserPassword = DigestUtils
                .md5DigestAsHex((userRegisterDTO.getUserPassword() + saltProperties.getPasswordSalt()).getBytes());
        // 5.2获取一个随机昵称
        String nickname = RandomUtil.randomString(UserConstant.RANDOM_NICKNAME_LENGTH);
        // 6.新增一个用户-添加默认字段
        User user = User.builder()
                .nickname(nickname)
                .userAccount(userRegisterDTO.getUserAccount())
                .userPassword(encryptUserPassword)
                .phone(userRegisterDTO.getPhone())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .userStatus(UserStatus.NORMAL)
                .build();
        userMapper.insert(user);
    }

    /**
     * 用户通过邮箱注册
     *
     * @param userRegisterByEmailDTO
     */
    @Override
    public boolean registerByEmail(UserRegisterByEmailDTO userRegisterByEmailDTO) {
        // 1.校验数据格式
        if (!CheckUtils.checkAccount(userRegisterByEmailDTO.getUserAccount())) {
            throw new WarnException(ExceptionConstant.ACCOUNT_ERROR);
        }
        if (!CheckUtils.checkPassword(userRegisterByEmailDTO.getUserPassword())) {
            throw new WarnException(ExceptionConstant.PASSWORD_ERROR);
        }
        if (!CheckUtils.checkEmail(userRegisterByEmailDTO.getEmail())) {
            throw new WarnException(ExceptionConstant.EMAIL_ERROR);
        }
        if (!CheckUtils.checkPhoneCode(userRegisterByEmailDTO.getCode())) {
            throw new WarnException(ExceptionConstant.EMAIL_CODE_ERROR);
        }
        // 2.根据邮箱查询是否有对应的验证码缓存
        // 2.1.没有返回验证码错误
        String key = RedisConstant.EMAIL_CODE_KEY + DigestUtils.md5DigestAsHex(userRegisterByEmailDTO.getEmail().getBytes());
        String result = stringRedisTemplate.opsForValue().get(key);
        if (result == null || result.isEmpty()) {
            throw new WarnException(ExceptionConstant.EMAIL_CODE_ERROR);
        }
        // 3.判断验证码是否正确 错误返回验证码错误
        if (!userRegisterByEmailDTO.getCode().equals(result)) {
            throw new WarnException(ExceptionConstant.EMAIL_CODE_ERROR);
        }
        // 验证码正确一次后直接失效
        stringRedisTemplate.delete(key);
        // 4.判断该邮箱/账号是否注册过 1.返回该邮箱已注册 2.返回账号已注册过请换一个
        checkEmailAndAccount(userRegisterByEmailDTO.getUserAccount(), userRegisterByEmailDTO.getEmail());
        // 5.密码加密
        String encryptUserPassword = DigestUtils
                .md5DigestAsHex((userRegisterByEmailDTO.getUserPassword() + saltProperties.getPasswordSalt()).getBytes());
        // 5.2获取一个随机昵称
        String nickname = RandomUtil.randomString(UserConstant.RANDOM_NICKNAME_LENGTH);
        // 6.新增一个用户-添加默认字段
        User user = User.builder()
                .nickname(nickname)
                .userAccount(userRegisterByEmailDTO.getUserAccount())
                .userPassword(encryptUserPassword)
                .email(userRegisterByEmailDTO.getEmail())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .userStatus(UserStatus.NORMAL)
                .build();
        int insert = userMapper.insert(user);
        return insert > 0;
    }

    /**
     * 通过账号登录
     *
     * @param userLoginDTO
     * @return
     */
    @Override
    public UserLoginVO loginByAccount(UserLoginDTO userLoginDTO) {
        // 1.校验用户账号和密码格式
        String userAccount = userLoginDTO.getUserAccount();
        String userPassword = userLoginDTO.getUserPassword();
        if (!CheckUtils.checkAccount(userAccount)) {
            throw new WarnException(ExceptionConstant.ACCOUNT_ERROR);
        }
        if (!CheckUtils.checkPassword(userPassword)) {
            throw new WarnException(ExceptionConstant.PASSWORD_ERROR);
        }
        // 2.校验验证码
        String code = userLoginDTO.getCode();
        VerifyServiceImpl.checkVerify(code, userLoginDTO.getKey(), stringRedisTemplate);
        // 3.查询账号密码是否正确 select * from user where user_account = ? and user_password = ?
        // 将密码转换为加密状态
        String transPassword = DigestUtils.md5DigestAsHex((userPassword + saltProperties.getPasswordSalt()).getBytes());
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUserAccount, userAccount)
                .eq(User::getUserPassword, transPassword);
        User user = userMapper.selectOne(lambdaQueryWrapper);
        if (BeanUtil.isEmpty(user)) {
            // 未查到说明用户名或密码错误
            throw new WarnException(ExceptionConstant.LOGIN_FAIL);
        }
        // 4.校验账号状态
        if (user.getUserStatus() == UserStatus.BANNED) {
            throw new BaseException(ExceptionConstant.ACCOUNT_EX_CODE, ExceptionConstant.ACCOUNT_EX);
        }
        // 5.生成token
        String token = UUID.randomUUID().toString();
        // 6.将token作为key将用户信息保存在redis
        redisUtils.saveUserInRedis(user, token);
        // 7.返回vo
        return UserLoginVO.builder()
                .id(user.getId())
                .userAccount(user.getUserAccount())
                .nickname(user.getNickname())
                .avatar(user.getAvatar())
                .token(token)
                .build();
    }

    /**
     * 通过token获取用户信息
     *
     * @return
     */
    @Override
    public UserInfoVO getUserInfoByToken() {
        // 获取当前用户
        UserSafetyDTO userSafetyDTO = UserBaseContext.getUser();
        // 获取用户完整信息
        User user = userMapper.selectById(userSafetyDTO.getId());
        // 返回VO
        UserInfoVO userInfoVO = BeanUtil.copyProperties(user, UserInfoVO.class);
        // 脱敏处理
        String phone = userInfoVO.getPhone();
        if (StrUtil.isNotEmpty(phone)) {
            // 保留前三位和后四位，中间四位用 **** 替换
            String safetyPhone = phone.substring(0, 3) + "****" + phone.substring(7);
            userInfoVO.setPhone(safetyPhone);
        }
        String email = userInfoVO.getEmail();
        if (StrUtil.isNotEmpty(email)) {
            // 查找邮箱的 @ 符号位置
            int atIndex = email.indexOf('@');
            if (atIndex > 0) {
                // 保留邮箱用户名的前两位，其余用 * 替换
                String username = email.substring(0, Math.min(2, atIndex));
                for (int i = 2; i < atIndex; i++) {
                    username += "*";
                }
                // 拼接脱敏后的邮箱
                String safetyEmail = username + email.substring(atIndex);
                userInfoVO.setEmail(safetyEmail);
            }
        }
        userInfoVO.setAppAuth(user.getAppAuth().getValue());
        userInfoVO.setCollectAuth(user.getCollectAuth().getValue());
        return userInfoVO;
    }

    /**
     * 用户编辑个人信息
     *
     * @param userEditDTO
     */
    @Override
    public void editUserInfo(UserEditDTO userEditDTO) {
        if (!CheckUtils.checkNickname(userEditDTO.getNickname())) {
            throw new WarnException(ExceptionConstant.NICKNAME_ERROR);
        }
        if (StrUtil.isNotEmpty(userEditDTO.getUserDesc()) && !CheckUtils.checkDescription(userEditDTO.getUserDesc())) {
            throw new WarnException(ExceptionConstant.DESC_ERROR);
        }
        Long currentId = UserBaseContext.getUser().getId();
        User user = userMapper.selectById(currentId);
        BeanUtil.copyProperties(userEditDTO, user);
        user.setUpdateTime(LocalDateTime.now());
        userMapper.updateById(user);
    }

    /**
     * 用户退出
     *
     * @param request
     */
    @Override
    public void userLogout(HttpServletRequest request) {
        String token = request.getHeader(tokenProperties.getUserTokenName());
        // 删除用户的登录状态
        Boolean result = redisUtils.deleteUserInRedis(token);
        if (Boolean.FALSE.equals(result)) {
            throw new BaseException(ErrorCode.SYSTEM_ERROR);
        }
    }

    /**
     * 分页查询
     *
     * @param userPageDTO
     * @return
     */
    @Override
    public PageResult<UserPageVO> pageQuery(UserPageDTO userPageDTO) {
        Page<User> page = userPageDTO.toMpPageDefaultSortByUpdateTimeDesc();
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.like(userPageDTO.getUserAccount() != null, User::getUserAccount, userPageDTO.getUserAccount())
                .like(userPageDTO.getNickname() != null, User::getNickname, userPageDTO.getNickname())
                .like(userPageDTO.getPhone() != null, User::getPhone, userPageDTO.getPhone())
                .between(userPageDTO.getBeginTime() != null && userPageDTO.getEndTime() != null,
                        User::getCreateTime, userPageDTO.getBeginTime(), userPageDTO.getEndTime());
        userMapper.selectPage(page, userLambdaQueryWrapper);
        return PageResult.of(page, UserPageVO.class);
    }

    /**
     * 新增用户
     *
     * @param userAddDTO
     */
    @Override
    public int addUser(UserAddDTO userAddDTO) {
        // 格式校验
        if (!CheckUtils.checkAccount(userAddDTO.getUserAccount())) {
            throw new BaseException(ExceptionConstant.ACCOUNT_ERROR);
        }
        if (!CheckUtils.checkPassword(userAddDTO.getUserPassword())) {
            throw new BaseException(ExceptionConstant.PASSWORD_ERROR);
        }
        if (StrUtil.isNotEmpty(userAddDTO.getEmail()) && !CheckUtils.checkEmail(userAddDTO.getEmail())) {
            throw new BaseException(ExceptionConstant.EMAIL_ERROR);
        }
        if (StrUtil.isNotEmpty(userAddDTO.getNickname()) && !CheckUtils.checkNickname(userAddDTO.getNickname())) {
            throw new BaseException(ExceptionConstant.NICKNAME_ERROR);
        }
        if (!CheckUtils.checkPhone(userAddDTO.getPhone())) {
            throw new BaseException(ExceptionConstant.PHONE_ERROR);
        }
        if (StrUtil.isNotEmpty(userAddDTO.getUserDesc()) && !CheckUtils.checkDescription(userAddDTO.getUserDesc())) {
            throw new BaseException(ExceptionConstant.DESC_ERROR);
        }
        // 判断手机号/账号是否已存在
        checkPhoneAndAccount(userAddDTO.getPhone(), userAddDTO.getUserAccount());
        // 4.判断该邮箱/账号是否注册过 1.返回该邮箱已注册 2.返回账号已注册过请换一个
        checkEmailAndAccount(userAddDTO.getUserAccount(), userAddDTO.getEmail());
        // 密码加密
        String encryptUserPassword = DigestUtils
                .md5DigestAsHex((userAddDTO.getUserPassword() + saltProperties.getPasswordSalt()).getBytes());
        // 新增一个用户-添加默认字段
        User user = User.builder()
                .nickname(userAddDTO.getNickname())
                .avatar(userAddDTO.getAvatar())
                .userAccount(userAddDTO.getUserAccount())
                .userPassword(encryptUserPassword)
                .email(userAddDTO.getEmail())
                .phone(userAddDTO.getPhone())
                .gender(userAddDTO.getGender())
                .userDesc(userAddDTO.getUserDesc())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .userStatus(UserStatus.NORMAL)
                .build();
        return userMapper.insert(user);
    }

    /**
     * 编辑用户
     *
     * @param userUpdateDTO
     * @return
     */
    @Override
    public int editUser(UserUpdateDTO userUpdateDTO) {
        if (StrUtil.isNotEmpty(userUpdateDTO.getNickname()) && !CheckUtils.checkNickname(userUpdateDTO.getNickname())) {
            throw new BaseException(ExceptionConstant.NICKNAME_ERROR);
        }
        if (StrUtil.isNotEmpty(userUpdateDTO.getEmail()) && !CheckUtils.checkEmail(userUpdateDTO.getEmail())) {
            throw new BaseException(ExceptionConstant.EMAIL_ERROR);
        }
        if (StrUtil.isNotEmpty(userUpdateDTO.getUserDesc()) && !CheckUtils.checkDescription(userUpdateDTO.getUserDesc())) {
            throw new BaseException(ExceptionConstant.DESC_ERROR);
        }
        User user = BeanUtil.copyProperties(userUpdateDTO, User.class);
        user.setAppAuth(AppAuthEnum.getEnumByValue(userUpdateDTO.getAppAuth()));
        user.setCollectAuth(CollectAuthEnum.getEnumByValue(userUpdateDTO.getCollectAuth()));
        user.setUpdateTime(LocalDateTime.now());
        return userMapper.updateById(user);
    }

    /**
     * 获取在线用户
     *
     * @return
     */
    @Override
    public List<UserOnlineVO> getOnlineUser() {
        return redisUtils.getAllUserInRedis();
    }

    /**
     * 重置密码
     *
     * @param id
     */
    @Override
    public void resetPw(Long id) {
        String userDefaultPassword = tokenProperties.getUserDefaultPassword();
        String pw = DigestUtils.md5DigestAsHex((userDefaultPassword + saltProperties.getPasswordSalt()).getBytes());
        User user = new User();
        user.setId(id);
        user.setUserPassword(pw);
        user.setUpdateTime(LocalDateTime.now());
        userMapper.updateById(user);
    }

    /**
     * 强制下线用户
     *
     * @param token
     */
    @Override
    public boolean offlineUser(String token) {
        if (StrUtil.isEmpty(token)) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        return redisUtils.delete(token);
    }

    /**
     * 设置用户状态
     *
     * @param status
     * @param id
     */
    @Override
    public void setUserStatus(Integer status, Long id) {
        // 如果设置为禁用状态，同时将该用户下线
        int code = UserStatus.BANNED.getCode();
        if (code == status) {
            redisUtils.deleteTokenById(id);
        }
        // 通过枚举的静态方法获取 UserStatus
        UserStatus userStatus = UserStatus.fromCode(status);
        // 设置用户状态
        User user = new User();
        user.setId(id);
        user.setUserStatus(userStatus);
        user.setUpdateTime(LocalDateTime.now());
        // 更新用户信息
        userMapper.updateById(user);
    }

    /**
     * 导出用户表格
     *
     * @param response
     * @param ids
     */
    @Override
    public void exportUserToExcel(HttpServletResponse response, List<Long> ids) {
        try {
            // 设置响应头
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("用户信息表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename=utf-8''" + fileName + ".xlsx");

            // 查询用户信息
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            List<User> userList;
            if (ids.isEmpty()) {
                userList = userMapper.selectList(queryWrapper);
            } else {
                userList = userMapper.selectBatchIds(ids);
            }

            // 转换为导出VO
            List<UserExportVO> exportVOList = userList.stream()
                    .map(user -> {
                        UserExportVO userExportVO = BeanUtil.copyProperties(user, UserExportVO.class);
                        userExportVO.setUserStatus(user.getUserStatus().getCode());
                        return userExportVO;
                    })
                    .collect(Collectors.toList());

            // 使用EasyExcel导出
            EasyExcel.write(response.getOutputStream(), UserExportVO.class)
                    .sheet("用户信息")
                    .doWrite(exportVOList);

        } catch (IOException e) {
            throw new RuntimeException(ExceptionConstant.EXPORT_EXCEL_ERROR, e);
        }
    }

    /**
     * 客户端根据关键词搜索
     *
     * @param searchPageDTO
     * @return
     */
    @Override
    public List<UserCardVO> searchUser(SearchPageDTO searchPageDTO) {
        // 1.校验参数
        String searchValue = searchPageDTO.getSearchValue();
        if (StrUtil.isBlank(searchValue)) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        // 2.开始分页
        Page<User> page = new Page<>(searchPageDTO.getCurrentPage(), ScrollingPageQuery.DEFAULT_PAGE_SIZE);
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.like(User::getNickname, searchValue)
                .eq(User::getUserStatus, UserStatus.NORMAL.getCode())
                .orderByDesc(User::getUpdateTime);
        userMapper.selectPage(page, userLambdaQueryWrapper);
        // 3.数据脱敏
        return page.getRecords().stream().map(user -> BeanUtil.copyProperties(user, UserCardVO.class)).toList();
    }

    /**
     * 通过id获取脱敏用户信息
     *
     * @param id
     * @return
     */
    @Override
    public UserHomePageVO getUserInfoById(Long id) {
        if (id == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        User user = userMapper.selectById(id);
        if (BeanUtil.isEmpty(user)) {
            throw new WarnException(ExceptionConstant.USER_NOT_EXIST);
        }
        if (user.getUserStatus().equals(UserStatus.BANNED)) {
            throw new WarnException(ExceptionConstant.USER_BANNED);
        }
        Long userId = UserBaseContext.getUser().getId();
        if (userId.equals(id)) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        Integer count = followMapper.selectIsFollowee(id, userId);
        if (count == null) {
            throw new BaseException(ErrorCode.SYSTEM_ERROR);
        }
        UserHomePageVO userHomePageVO = BeanUtil.copyProperties(user, UserHomePageVO.class);
        userHomePageVO.setFollowFlag(count > 0);
        return userHomePageVO;
    }

    /**
     * 滚动分页查询id对应用户的粉丝用户卡片
     *
     * @param userCardPageQuery
     * @return
     */
    @Override
    public List<UserCardVO> getFansPage(UserCardPageQuery userCardPageQuery) {
        // 1.校验参数
        Long userId = userCardPageQuery.getId();
        if (userId == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        // 2.开始分页R
        Page<UserFollow> page = new Page<>(userCardPageQuery.getCurrentPage(), ScrollingPageQuery.DEFAULT_PAGE_SIZE);
        LambdaQueryWrapper<UserFollow> userFollowLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userFollowLambdaQueryWrapper.eq(UserFollow::getFollowUserId, userId);
        followMapper.selectPage(page, userFollowLambdaQueryWrapper);
        if (page.getRecords().isEmpty()) {
            return Collections.emptyList();
        }
        // 3.封装数据
        List<Long> userIds = page.getRecords().stream().map(UserFollow::getUserId).toList();
        List<User> users = userMapper.selectBatchIds(userIds);
        return users.stream().map(user -> BeanUtil.copyProperties(user, UserCardVO.class)).toList();
    }

    /**
     * 滚动分页查询id对应用户的关注用户卡片
     *
     * @param userCardPageQuery
     * @return
     */
    @Override
    public List<UserCardVO> getFollowsPage(UserCardPageQuery userCardPageQuery) {
        // 1.校验参数
        Long userId = userCardPageQuery.getId();
        if (userId == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        // 2.开始分页
        Page<UserFollow> page = new Page<>(userCardPageQuery.getCurrentPage(), ScrollingPageQuery.DEFAULT_PAGE_SIZE);
        LambdaQueryWrapper<UserFollow> userFollowLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userFollowLambdaQueryWrapper.eq(UserFollow::getUserId, userId);
        followMapper.selectPage(page, userFollowLambdaQueryWrapper);
        if (page.getRecords().isEmpty()) {
            return Collections.emptyList();
        }
        // 3.封装数据
        List<Long> userIds = page.getRecords().stream().map(UserFollow::getFollowUserId).toList();
        List<User> users = userMapper.selectBatchIds(userIds);
        return users.stream().map(user -> BeanUtil.copyProperties(user, UserCardVO.class)).toList();
    }

    /**
     * 客户端设置应用访问权限
     *
     * @return
     */
    @Override
    public boolean setAppAuth() {
        Long id = UserBaseContext.getUser().getId();
        User user = userMapper.selectById(id);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        if (user.getAppAuth().getValue() == AppAuthEnum.HIDDEN.getValue()) {
            user.setAppAuth(AppAuthEnum.VISIBLE);
        } else if (user.getAppAuth().getValue() == AppAuthEnum.VISIBLE.getValue()) {
            user.setAppAuth(AppAuthEnum.HIDDEN);
        }
        user.setUpdateTime(LocalDateTime.now());
        int i = userMapper.updateById(user);
        return i > 0;
    }

    /**
     * 客户端设置收藏访问权限
     *
     * @return
     */
    @Override
    public boolean setCollectAuth() {
        Long id = UserBaseContext.getUser().getId();
        User user = userMapper.selectById(id);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        if (user.getCollectAuth().getValue() == CollectAuthEnum.VISIBLE.getValue()) {
            user.setCollectAuth(CollectAuthEnum.HIDDEN);
        } else if (user.getCollectAuth().getValue() == CollectAuthEnum.HIDDEN.getValue()) {
            user.setCollectAuth(CollectAuthEnum.VISIBLE);
        }
        user.setUpdateTime(LocalDateTime.now());
        int i = userMapper.updateById(user);
        return i > 0;
    }

    /**
     * 客户端修改密码
     *
     * @param userRePwDTO
     * @return
     */
    @Override
    public boolean resetUserPassword(UserRePwDTO userRePwDTO) {
        // 1.格式校验
        String newPassword = userRePwDTO.getNewPassword();
        String oldPassword = userRePwDTO.getOldPassword();
        if (!CheckUtils.checkPassword(oldPassword) || !CheckUtils.checkPassword(newPassword)) {
            throw new BaseException(ExceptionConstant.PASSWORD_ERROR);
        }
        // 2.检查旧密码是否正确
        Long id = UserBaseContext.getUser().getId();
        User user = userMapper.selectById(id);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        String transOldPassword = DigestUtils.md5DigestAsHex((oldPassword + saltProperties.getPasswordSalt()).getBytes());
        if (!transOldPassword.equals(user.getUserPassword())) {
            throw new BaseException(ExceptionConstant.OLD_PASSWORD_ERROR);
        }
        // 3.设置新密码
        String transNewPassword = DigestUtils.md5DigestAsHex((newPassword + saltProperties.getPasswordSalt()).getBytes());
        user.setUserPassword(transNewPassword);
        user.setUpdateTime(LocalDateTime.now());
        int i = userMapper.updateById(user);
        return i > 0;
    }

    private void checkPhoneAndAccount(String phone, String userAccount) {
        User byPhone = userMapper.selectByPhone(phone);
        if (BeanUtil.isNotEmpty(byPhone)) {
            throw new BaseException(ExceptionConstant.PHONE_REGISTERED);
        }
        User byUserAccount = userMapper.selectByUserAccount(userAccount);
        if (BeanUtil.isNotEmpty(byUserAccount)) {
            throw new BaseException(ExceptionConstant.ACCOUNT_NOT_UNIQUE);
        }
    }

    private void checkEmailAndAccount(String userAccount, String email) {
        User byEmail = userMapper.selectByEmail(email);
        if (BeanUtil.isNotEmpty(byEmail)) {
            throw new BaseException(ExceptionConstant.EMAIL_REGISTERED);
        }
        User byUserAccount = userMapper.selectByUserAccount(userAccount);
        if (BeanUtil.isNotEmpty(byUserAccount)) {
            throw new BaseException(ExceptionConstant.ACCOUNT_NOT_UNIQUE);
        }
    }
}




